package main;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.Hashtable;

import javax.swing.*;

/**
 * A library that holds a list of all images loaded.
 * 
 * @author John Lattin
 */
public class ImageLibrary
{
	private static final long serialVersionUID = 1L;

	public static Hashtable<String,BufferedImage> images = new Hashtable<String,BufferedImage>( );
	private static JPanel panel = new JPanel( );

	/**
	 * Returns an image that is stored in the library of given name.
	 * @param name - the name of the image you wish to be returned.
	 * @return the image.
	 */
	public static BufferedImage get( String name )
	{
		if( images.get(name) == null ) {
			return null;
		}
		return images.get( name );
	}

	public static boolean contains( String name )
	{
		return images.containsKey( name );
	}

	public static BufferedImage add( String name , BufferedImage img )
	{
		images.put( name , img );
		return images.get( name );
	}

	public static void set( String name , BufferedImage img )
	{
		add( name , img );
	}

	public static void resize( String name , double scaleX , double scaleY )
	{
		BufferedImage bufimg = getScaledBufferedImage( images.get( name ) , scaleX , scaleY );
		set( name , bufimg );
	}

	public static BufferedImage getScaledBufferedImage( BufferedImage image , double scaleX , double scaleY )
	{
		AffineTransform trans = new AffineTransform( );
		trans.scale( scaleX , scaleY );
		AffineTransformOp op = new AffineTransformOp( trans ,
				AffineTransformOp.TYPE_BILINEAR );
		return op.filter( image , null );
	}

	/**
	 * Add an image to the library of given name and location.
	 * 
	 * @param name - name of the image.
	 * @param location - the location of the image to be added to the library.
	 * @return the image that was added.
	 */
	public static BufferedImage add( String name , String location )
	{
		BufferedImage bufimg = load( location );
		return add( name , bufimg );
	}

	/**
	 * Add an image to the library of given name and absolute location.
	 * 
	 * @param name - name of the image.
	 * @param absoluteLocation - the absolute location of the image to be added to the library.
	 * @return the image that was added.
	 */
	public static BufferedImage addImage( String name , String absoluteLocation )
	{
		BufferedImage bufimg = loadAbsolute( absoluteLocation );
		return add( name , bufimg );
	}

	/**
	 * Add an image set to the library.  An image set is a set of images
	 * 	from a single image.
	 * 
	 * --------
	 * 0| 1| 2|
	 * 3| 4| 5|
	 * 6| 7| 8|
	 * 9|10|11|
	 * --------
	 * 
	 * background[0], background[1], background[2], background[3] ... background[11]
	 * 
	 * If the name is background, the across is 3 and the down is 4 then the
	 * 	above diagram shows the numbering system and the naming system.
	 * 
	 * @param name - name of the image set.
	 * @param location - location o the image.
	 * @param across - the number of images across you wish to break the image into.
	 * @param down - the number of images down you wish to break the image into.
	 */
	public static void addSet( String name , String location , int across , int down )
	{
		BufferedImage bufimgTemp = load( location );

		int width = 0;
		int height = 0;
		try{
			width = bufimgTemp.getWidth( panel )/across;
			height = bufimgTemp.getHeight( panel )/down;
			BufferedImage bufimg[] = new BufferedImage[down*across];
			for( int i = 0, index = 0; i < down; i++ )
			{
				for( int j = 0; j < across; j++, index++ )
				{
					bufimg[index] = bufimgTemp.getSubimage( j * width , i*height , width , height );
					add( name + "[" + index + "]" , bufimg[index] );
				}
			}
		} catch( Exception e ){ e.printStackTrace( ); }
	}

	private static BufferedImage load( String location )
	{
		BufferedImage bufimg = null;
		try{
			bufimg = getBufferedImage( "" + location , panel );
		}catch(Exception e){}
		if( bufimg == null )
		{
			System.out.println( "IMAGES: null bufimg" );
			return null;
		}
		return bufimg;
	}

	private static BufferedImage loadAbsolute( String location )
	{
		BufferedImage bufimg = null;
		try{
			bufimg = getBufferedImage( location , panel );
		}catch(Exception e){}
		if( bufimg == null )
		{
			System.out.println( "IMAGES: null bufimg" );
			return null;
		}
		return bufimg;
	}

	private static BufferedImage getBufferedImage(String imageFile, Component c) {
		URL u = null;
		//System.out.println( "Trying to find: " + imageFile );
		try {u = new URL(imageFile);} catch ( java.net.MalformedURLException ex ) {}
        if ( u == null )
                u = ImageLibrary.class.getClassLoader().getResource(imageFile);
        //System.out.println( "Trying to find: " + u );
		Image image = c.getToolkit().getImage(u);
		waitForImage(image, c);
		try {
			BufferedImage bufferedImage = new BufferedImage(image.getWidth(c),
					image.getHeight(c), BufferedImage.TYPE_INT_ARGB);
			Graphics2D g2d = bufferedImage.createGraphics();
			g2d.drawImage(image, 0, 0, c);
			return (bufferedImage);
		} catch (Exception e) {
			System.out.println("FileHandeler: Could Not Find Image: " + imageFile);
			e.printStackTrace( );
		}
		return null;
	}

	private static boolean waitForImage(Image image, Component c) {
		MediaTracker tracker = new MediaTracker(c);
		tracker.addImage(image, 0);
		try {tracker.waitForAll();}
		catch (InterruptedException ie) {}
		return (!tracker.isErrorAny());
	}
}
